package com.graduation.project.service.process.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.graduation.project.entity.dto.*;
import com.graduation.project.entity.dto.grade.SaveOrUpdateGradeDTO;
import com.graduation.project.entity.dto.thesis.ListThesisDTO;
import com.graduation.project.entity.other.LoginUser;
import com.graduation.project.entity.po.Grade;
import com.graduation.project.entity.po.Thesis;
import com.graduation.project.entity.vo.ListThesisVO;
import com.graduation.project.enums.ResultCodeEnum;
import com.graduation.project.mapper.grade.GradeMapper;
import com.graduation.project.mapper.process.ListThesisMapper;
import com.graduation.project.mapper.process.ThesisMapper;
import com.graduation.project.service.process.ThesisService;
import com.graduation.project.utils.FileUtil;
import com.graduation.project.utils.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ThesisServiceImpl extends ServiceImpl<ThesisMapper, Thesis> implements ThesisService {

    @Autowired
    private ThesisMapper thesisMapper;
    @Autowired
    private ListThesisMapper listThesisMapper;
    @Autowired
    private GradeMapper gradeMapper;

    @Override
    public void createThesis(Long taskId, Integer type) {
        // 判断论文数据是否已存在
        LambdaQueryWrapper<Thesis> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Thesis::getTaskId, taskId)
                .eq(Thesis::getThesisType, type);
        List<Thesis> thesisList = thesisMapper.selectList(lambdaQueryWrapper);
        if (CollUtil.isNotEmpty(thesisList)) {
            throw new RuntimeException("论文数据已存在");
        }

        Thesis thesis = new Thesis();
        thesis.setTaskId(taskId);
        // 设置论文类型
        thesis.setThesisType(type);
        try {
            thesisMapper.insert(thesis);
        }catch (Exception e) {
            throw new RuntimeException("创建失败");
        }
    }

    @Override
    public ResultUtil<?> listThesisByCondition(ListThesisDTO input) {
        IPage<ListThesisVO> page = new Page<>();
        page.setCurrent(input.getCurrentPage());
        page.setSize(input.getPageSize());
        listThesisMapper.listThesisByCondition(page, input);

        Map<String, Object> map = new HashMap<>();
        map.put("listThesisVo", page.getRecords());
        map.put("total", page.getTotal());

        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "查询成功", map);
    }

    @Override
    public ResultUtil<?> auditThesis(UpdateStatusDTO input) {
        // 判断论文数据是否存在
        LambdaQueryWrapper<Thesis> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Thesis::getId, input.getId());
        Thesis thesis = thesisMapper.selectOne(lambdaQueryWrapper);
        if (ObjectUtil.isEmpty(thesis)) {
            throw new RuntimeException("数据不存在");
        }
        // 审核
        thesis.setAuditStatus(input.getStatus());
        thesis.setAuditIdea(input.getIdea());
        try {
            thesisMapper.updateById(thesis);
            // 如果审核通过
            if (input.getStatus().equals(1)) {
                // 如果当前审核的是初稿，生成一条定稿数据
                if (thesis.getThesisType().equals(0)) {
                    this.createThesis(thesis.getTaskId(), 1);
                }
                // 如果当前审核的是定稿，生成一条最终稿数据
                if (thesis.getThesisType().equals(1)) {
                    this.createThesis(thesis.getTaskId(), 2);
                }
                // 如果当前审核的是最终稿，就啥也不干
            }
        } catch (Exception e) {
            throw new RuntimeException("审核失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "审核成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> gradeThesis(SaveOrUpdateGradeDTO input) {
        if (ObjectUtil.isEmpty(input.getProcessScore())) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "过程评价成绩不能为空");
        }
        // 判断所评是否存在
        LambdaQueryWrapper<Grade> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Grade::getTaskId, input.getTaskId())
                .eq(Grade::getGradeType, input.getGradeType());
        Grade res = gradeMapper.selectOne(lambdaQueryWrapper);

        UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authenticationToken.getPrincipal();
        String userCode = loginUser.getUser().getUserCode();

        if (ObjectUtil.isNotEmpty(res)) {
            // 重评
            res.setTopicScore(input.getTopicScore());
            res.setProcessScore(input.getProcessScore());
            res.setAbilityScore(input.getAbilityScore());
            res.setQualityScore(input.getQualityScore());
            res.setGradeScore(input.getTopicScore() + input.getProcessScore() + input.getAbilityScore() + input.getQualityScore());
            res.setGradeRemark(input.getGradeRemark());
            res.setUserCode(userCode);
            try {
                gradeMapper.updateById(res);
            } catch (Exception e) {
                throw new RuntimeException("评分失败");
            }
        } else {
            Grade grade = new Grade();
            BeanUtil.copyProperties(input, grade);
            grade.setGradeScore(input.getTopicScore() + input.getProcessScore() + input.getAbilityScore() + input.getQualityScore());
            grade.setUserCode(userCode);
            try {
                gradeMapper.insert(grade);
            } catch (Exception e) {
                throw new RuntimeException("评分失败");
            }
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "评分成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> allotEvaluator(AllotDTO input) {
        LambdaUpdateWrapper<Thesis> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Thesis::getId, input.getId())
                .set(Thesis::getEvaluatorCode, input.getCode());
        try {
            thesisMapper.update(null, lambdaUpdateWrapper);
        }catch (Exception e) {
            throw new RuntimeException("分配失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "分配成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> allotDefense(AllotDTO input) {
        LambdaUpdateWrapper<Thesis> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Thesis::getId, input.getId())
                .set(Thesis::getGroupCode, input.getCode());
        try {
            thesisMapper.update(null, lambdaUpdateWrapper);
        }catch (Exception e) {
            throw new RuntimeException("分配失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "分配成功");
    }

    @Override
    public ResultUtil<?> uploadThesisFile(UploadFileDTO input) {
        if (ObjectUtil.isEmpty(input.getFile())) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "上传文件不能为空");
        }
        // 判断数据是否存在
        Thesis thesis = thesisMapper.selectOne(new LambdaQueryWrapper<Thesis>().eq(Thesis::getId, input.getId()));
        if (ObjectUtil.isEmpty(thesis)) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "数据不存在");
        }
        // 获取用户信息
        UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authenticationToken.getPrincipal();
        // 获取用户上传文件后缀，并通过uuid命名文件
        String fileName = input.getFile().getOriginalFilename();
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        fileName = IdUtil.simpleUUID() + suffix;
        String filePath = "public/static/zyf_file/" + loginUser.getUser().getUserCode() + "/" + input.getFileType() + "/";
        thesis.setFilePath(filePath + fileName);
        thesis.setAuditStatus(0);
        try {
            // 保存到数据库（保存相对路径）
            thesisMapper.updateById(thesis);
            // 上传文件
            FileUtil.uploadFile(input.getFile(), filePath, fileName);
        }catch (Exception e) {
            throw new RuntimeException("上传失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "上传成功");
    }

    @Override
    public ResultUtil<?> deleteThesisFile(DeleteFileDTO input) {
        // 判断数据是否存在
        Thesis thesis = thesisMapper.selectOne(new LambdaQueryWrapper<Thesis>().eq(Thesis::getId, input.getId()));
        if (ObjectUtil.isEmpty(thesis)) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "数据不存在");
        }
        thesis.setFilePath("");
        try {
            // 清空file_path字段
            thesisMapper.updateById(thesis);
        }catch (Exception e) {
            throw new RuntimeException("删除失败");
        }
        try {
            // 删除文件
            FileUtil.deleteFile(input.getFilePath());
        }catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "删除成功");
    }

    @Override
    public ResultUtil<?> getThesisGrade(Long taskId) {
        Grade grade = gradeMapper.selectOne(new LambdaQueryWrapper<Grade>()
                .eq(Grade::getGradeType, 0)
                .eq(Grade::getTaskId, taskId));
        Map<String, Object> map = new HashMap<>();

        if (ObjectUtil.isNotEmpty(grade)) {
            map.put("gradeScore", grade.getGradeScore());
            map.put("gradeRemark", grade.getGradeRemark());
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS, map);
    }
}
